package cn.com.heaton.blelibrary.ble;


import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.os.Handler;

import com.blankj.utilcode.util.ThreadUtils;
import com.ioidea.base.util.MyLogger;

import java.util.List;
import java.util.UUID;

import cn.com.heaton.blelibrary.ble.callback.BleConnectCallback;
import cn.com.heaton.blelibrary.ble.callback.BleNotifyCallback;
import cn.com.heaton.blelibrary.ble.callback.BleScanCallback;
import cn.com.heaton.blelibrary.ble.callback.BleStatusCallback;
import cn.com.heaton.blelibrary.ble.callback.BleWriteCallback;
import cn.com.heaton.blelibrary.ble.callback.BleWriteEntityCallback;
import cn.com.heaton.blelibrary.ble.model.BleDevice;
import cn.com.heaton.blelibrary.ble.queue.RequestTask;
import cn.com.heaton.blelibrary.ble.utils.ByteUtils;

/**
 * 1 二维码读取。
 * 716F277F&V3.0.1&V5.3.S&11&8&SL-G1-G
 * 2 BLE写
 * 0xAB + 0xBA + 0xAC + 0xCA + 内容长度 + 内容
 * 内容 ：716F277F&V3.0.1&V5.3.S&11&8&SL-G1-G&1&430.2&https://www-city-light.ioidea.net/splms-web/deviceAccess&CMNET&NULL&NULL&ioidea&iot123$&89
 * 3 BLE回
 * 0xAB + 0xBA + 0xAC + 0xCB + 内容前8字节 + 成功标识
 * 内容前8字节：716F277F
 * 成功标识 ：0x01 写入成功 0x00 写入失败 （重写）
 */
public class BleManage {




    private static BleManage instance;
    private State mState = State.NOT_CONNECTED;
    public final Ble<BleRssiDevice> mBle;
    private BleRssiDevice mBleDevice;
    private BluetoothGattCharacteristic mBluetoothGattCharacteristic;
    private ConnectStateListener mStateListener;
    private NotifyListener mNotifyListener;
    private WirteListener mWirteListener;
    private boolean is_neet_reset_scan = false;
    public int TIMEOUT = 30 * 1000;//超时时间
    private int requestIndex;

    public static String resultStr;

    //bleToLora写入成功后 回数据会回20遍
    public boolean isReceiveing;
    public String mSn;

    private BleManage() {
        mBle = Ble.getInstance();
        mBle.setBleStatusCallback(new BleStatusCallback() {
            @Override
            public void onBluetoothStatusChanged(boolean isOn) {
                if (isOn) {
                    if (mState.getValue() <= State.NOT_CONNECTED.getValue()) {
                        updateState(State.NOT_CONNECTED);
                        //TODO 这里可以去自动扫描
                    }
                } else {
                    is_neet_reset_scan = true;
                    updateState(State.DISABLE);
                }
            }
        });
    }

    public static BleManage getInstance() {
        if (instance == null) {
            synchronized (BleManage.class) {
                if (instance == null) {
                    instance = new BleManage();
                }
            }
        }
        return instance;
    }

    public List<BleRssiDevice> getConnectedDevices() {
//        List<BleRssiDevice> connectedDevices = mBle.getConnectedDevices();
        return mBle.getConnectedDevices();
    }


    private BleConnectCallback<BleRssiDevice> connectCallback = new BleConnectCallback<BleRssiDevice>() {
        @Override
        public void onConnectionChanged(BleRssiDevice device) {
            if (device.isConnected()) {
                updateState(State.CONNECTED);
                MyLogger.hLog().i("已连接");
                mBleDevice = device;
                is_neet_reset_scan = false;
            } else if (device.isConnecting()) {
                updateState(State.CONNECTING);
                MyLogger.hLog().i("连接中...");
            } else if (device.isDisconnected()) {
                updateState(State.NOT_CONNECTED);
                MyLogger.hLog().i("未连接");
            }
        }

        @Override
        public void onConnectFailed(BleRssiDevice device, int errorCode) {
            super.onConnectFailed(device, errorCode);
            updateState(State.NOT_CONNECTED);
        }


        @Override
        public void onConnectCancel(BleRssiDevice device) {
            super.onConnectCancel(device);
            updateState(State.NOT_CONNECTED);
            MyLogger.hLog().e("onConnectCancel: " + device.getBleName());
        }

        @Override
        public void onServicesDiscovered(BleRssiDevice device, BluetoothGatt gatt) {
            super.onServicesDiscovered(device, gatt);
            List<BluetoothGattService> services = gatt.getServices();
            //获取指定服务
            BluetoothGattService characteristic = services.get(2);
            List<BluetoothGattCharacteristic> characteristics = characteristic.getCharacteristics();
//            mBluetoothGattCharacteristic = characteristics.get(2);
            //开启监听
//            notifyBle(device, mBluetoothGattCharacteristic);
            for (BluetoothGattCharacteristic bluetoothGattCharacteristic : characteristics) {
                int charaProp = bluetoothGattCharacteristic.getProperties();
                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) {
                    mBluetoothGattCharacteristic = bluetoothGattCharacteristic;
                } else if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
                    notifyBle(device, bluetoothGattCharacteristic);
                }
            }
        }

        @Override
        public void onReady(BleRssiDevice device) {
            super.onReady(device);
        }
    };

    //开启监听
    public void notifyBle(BleDevice device, BluetoothGattCharacteristic characteristic) {
        MyLogger.hLog().i("notifyBle 创建回调");
        Ble.getInstance().enableNotifyByUuid(
                device,
                true,
                characteristic.getService().getUuid(),
                characteristic.getUuid(),
                new BleNotifyCallback<BleDevice>() {
                    @Override
                    public void onChanged(BleDevice device, BluetoothGattCharacteristic characteristic) {
                        MyLogger.hLog().i("收到数据成功 ====byte========> " + characteristic.getValue());
                        String msg = ByteUtils.bytes2HexStr(characteristic.getValue());
                        resultStr = msg;
                        MyLogger.hLog().i("收到数据成功 ============> " + msg);
                        receive(msg);
                    }

                    @Override
                    public void onNotifySuccess(BleDevice device) {
                        super.onNotifySuccess(device);
                        //启用通知
                        MyLogger.hLog().i("收到数据回调 ============> Notifications_enabled");
                    }

                    @Override
                    public void onNotifyCanceled(BleDevice device) {
                        super.onNotifyCanceled(device);
                        MyLogger.hLog().i("收到数据回调 ============> Notifications and indications disabled");
                    }
                });
        updateState(State.SUCCESS);
    }                   // 关闭通知


    /**
     * 协议定义的不够通用  应该各自解析成功 失败
     * BleToLora的解析很简单先暂时这样处理
     * @param hexStr  16进制字符串
     */
    private synchronized void receive(String hexStr) {
        //bleToLora需要使用16进制判断  所以没有统一转换成String
        MyLogger.hLog().i("十六进制:" + hexStr);
        removeTimeout();
        //处理蓝牙转lora的逻辑
        runOnUiThread(()->{
            if (mWirteListener!=null){
                mWirteListener.callback( hexStr);
            }

        });
    }


    /**
     * 在主线程回调
     */
    private void runOnUiThread(Runnable runnable) {
        ThreadUtils.runOnUiThread(() -> runnable.run());
    }

    public void scan(BleScanCallback<BleRssiDevice> scanCallback2) {
        if (mBle.isScanning()) {
            mBle.stopScan();
        }
        updateState(State.SCANING);
        mBle.startScan(scanCallback2);
    }

    /**
     * 重新连接
     */
    public void resetConnect(BleScanCallback<BleRssiDevice> scanCallback) {
        if (!is_neet_reset_scan && mBleDevice != null) {//不需要扫描,直连
            MyLogger.hLog().i("直连=================");
            connectBle(mBleDevice);
        } else {//需要扫描
            MyLogger.hLog().i("扫描=================");
            scan(scanCallback);//扫描后会自动去连接
        }
    }

    /**
     * 连接蓝牙
     */
    public void connectBle(BleRssiDevice device) {
        if (mBle.isScanning()) {
            mBle.stopScan();
        }
        updateState(State.CONNECTING);
        mBle.connect(device, connectCallback);
    }

    private void updateState(State state) {
        mState = state;
        runOnUiThread(() -> {
            if (mStateListener != null) {
                mStateListener.onConnectionChanged(mState);
            }
        });
    }

    //设置全局监听
    public void setConnectStateListener(ConnectStateListener listener) {
        this.mStateListener = listener;
    }

    //设置全局监听
    public void setNotifyListener(NotifyListener listener) {
        this.mNotifyListener = listener;
    }






    /**
     * 超时处理
     */
    Handler mHandler = new Handler();
    Runnable timeoutRunable = new Runnable() {
        @Override
        public void run() {
            if (mWirteListener != null) {
                mWirteListener.callback( "");
            }
        }
    };


    public void addTimeout() {
        mHandler.postDelayed(timeoutRunable, TIMEOUT);
    }

    public void removeTimeout() {
        mHandler.removeCallbacks(timeoutRunable);
    }




    String firstStr = "";
    String lastStr = "";

    public void writeData(String sn, String dataStr, WirteListener listener) {
        requestIndex = 0;
        mSn = sn;
        mWirteListener = listener;
        boolean isBigData = false;
        if (mBleDevice == null || mBluetoothGattCharacteristic == null) {
            if (listener != null) {
                listener.callback( "");
            }
            return;
        }
        UUID serviceUUID = mBluetoothGattCharacteristic.getService().getUuid();
        UUID characteristicUUID = mBluetoothGattCharacteristic.getUuid();

        MyLogger.hLog().e("serviceUUID:"+serviceUUID);
        MyLogger.hLog().e("characteristicUUID:"+characteristicUUID);
        if (dataStr.length() >= 200) {
            firstStr = dataStr.substring(0, 200);
            lastStr = dataStr.substring(200);
            MyLogger.hLog().i("firstStr:" + firstStr);
            MyLogger.hLog().i("lastStr:" + lastStr);
            isBigData = true;
        }

        MyLogger.hLog().i("isBigData:" + isBigData);

        if (!isBigData) {
            writeByUuid(mBleDevice, dataStr.getBytes(), serviceUUID, characteristicUUID, new BleWriteCallback<BleRssiDevice>() {
                @Override
                public void onWriteSuccess(BleRssiDevice device, BluetoothGattCharacteristic characteristic) {
                    MyLogger.hLog().d("onWriteSuccess1 ============>");
                    addTimeout();
                }

                @Override
                public void onWriteFailed(BleRssiDevice device, int failedCode) {
                    super.onWriteFailed(device, failedCode);
                    if (listener != null) {
                        listener.callback("");
                    }
                    MyLogger.hLog().d("w发送数据失败 ============> " + failedCode);
                }
            });
        } else {
            requestIndex++;
            writeByUuid(mBleDevice, firstStr.getBytes(), serviceUUID, characteristicUUID, new BleWriteCallback<BleRssiDevice>() {
                @Override
                public void onWriteSuccess(BleRssiDevice device, BluetoothGattCharacteristic characteristic) {
                    MyLogger.hLog().d("onWriteSuccess1 ============>");
                    requestIndex++;
                    if (requestIndex == 2) {
                        writeByUuid(mBleDevice, lastStr.getBytes(), serviceUUID, characteristicUUID, new BleWriteCallback<BleRssiDevice>() {
                            @Override
                            public void onWriteSuccess(BleRssiDevice device, BluetoothGattCharacteristic characteristic) {
                                MyLogger.hLog().d("onWriteSuccess2 ============>");
                                //添加超时
                                addTimeout();
                            }

                            @Override
                            public void onWriteFailed(BleRssiDevice device, int failedCode) {
                                super.onWriteFailed(device, failedCode);
                                if (listener != null) {
                                    listener.callback( "");
                                }
                                MyLogger.hLog().d("n发送数据失败 ============> " + failedCode);
                            }
                        });
                    }

                }

                @Override
                public void onWriteFailed(BleRssiDevice device, int failedCode) {
                    super.onWriteFailed(device, failedCode);
                    if (listener != null) {
                        listener.callback("");
                    }
                    MyLogger.hLog().d("w发送数据失败 ============> " + failedCode);
                }
            });
        }
    }

    public void writeBigData(String sn, String dataStr, WirteListener listener) {
        requestIndex = 0;
        mSn = sn;
        mWirteListener = listener;
        boolean isBigData = false;
        if (mBleDevice == null || mBluetoothGattCharacteristic == null) {
            if (listener != null) {
                listener.callback( "");
            }
            return;
        }
        UUID serviceUUID = mBluetoothGattCharacteristic.getService().getUuid();
        UUID characteristicUUID = mBluetoothGattCharacteristic.getUuid();

        MyLogger.hLog().e("serviceUUID:"+serviceUUID);
        MyLogger.hLog().e("characteristicUUID:"+characteristicUUID);
        if (dataStr.length() >= 200) {
            firstStr = dataStr.substring(0, 200);
            lastStr = dataStr.substring(200);
            MyLogger.hLog().i("firstStr:" + firstStr);
            MyLogger.hLog().i("lastStr:" + lastStr);
            isBigData = true;
        }

        MyLogger.hLog().i("isBigData:" + isBigData);

        byte[]data = {1,2};
        mBle.writeEntity(mBle.getConnectedDevices().get(0), data, 20, 50, new BleWriteEntityCallback<BleRssiDevice>() {
            @Override
            public void onWriteSuccess() {

            }

            @Override
            public void onWriteFailed() {

            }
        });

    }


    /**
     * 蓝牙转lora 调用
     *
     */
    private void writeByUuid(BleRssiDevice mBleDevice, byte[] bytes, UUID serviceUUID, UUID characteristicUUID, BleWriteCallback<BleRssiDevice> bleWriteCallback) {
        //通过特定服务和特征值uuid写入数据
        mBle.writeByUuid(mBleDevice, bytes, serviceUUID, characteristicUUID, bleWriteCallback);
    }



    public void stopScan() {
        if (Ble.getInstance().isScanning()) {
            Ble.getInstance().stopScan();
        }
    }

    public State getState() {
        return mState;
    }

    public void removeListener() {
        mStateListener = null;
        mNotifyListener = null;
        mWirteListener = null;
    }

    /**
     * 断开蓝牙
     */
    public void disconnect() {
        if (mBleDevice != null) {
            Ble.getInstance().disconnect(mBleDevice);
        }
    }




    public interface ConnectStateListener {
        /**
         * 状态回调
         *
         * @param state
         */
        void onConnectionChanged(State state);

        /**
         * 获取服务后并开启了通知得回调
         */
        void onSuccess();
    }

    public interface NotifyListener {
        void notify(String msg);
    }

    public interface WirteListener {
        void callback( String snStr);
    }

    public enum State {
        DISABLE(0),//未启用蓝牙
        NOT_CONNECTED(1),//未连接
        SCANING(2),//扫描中
        CONNECTING(3),//连接中
        CONNECTED(4),//已连接
        SUCCESS(5);//监听服务开启成功
        int value;

        State(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }

    }
}
